#define _CRT_SECURE_NO_WARNINGS

#include "printers.h"
#include "pe.h"
#include "file_cmd.h"
#include "int_util.h"
#include <time.h>
#include <stdlib.h>
#include <stdio.h>

/****************************************************************************\
 * Private Variables/Functions
\****************************************************************************/

static str_wc s_dd_names[] =
{
	L"EXPORT",          //  0
	L"IMPORT",          //  1
	L"RESOURCE",        //  2
	L"EXCEPTION",       //  3
	L"SECURITY",        //  4
	L"BASERELOC",       //  5
	L"DEBUG",           //  6
	L"ARCHITECTURE",    //  7 
	L"GLOBALPTR",       //  8
	L"TLS",             //  9
	L"LOAD_CONFIG",     // 10
	L"BOUND_IMPORT",    // 11
	L"IAT",             // 12
	L"DELAY_IMPORT",    // 13
	L"COM_DESCRIPTOR",  // 14
	L""                 // 15
};

static void s_print_file_machine(u2 machine)
{
	switch(machine)
	{
	case IMAGE_FILE_MACHINE_UNKNOWN:
		wprintf(L"(IMAGE_FILE_MACHINE_UNKNOWN)");
		break;
	case IMAGE_FILE_MACHINE_I386:
		wprintf(L"(IMAGE_FILE_MACHINE_I386)");
		break;
	case IMAGE_FILE_MACHINE_R3000:
		wprintf(L"(IMAGE_FILE_MACHINE_R3000)");
		break;
	case IMAGE_FILE_MACHINE_R4000:
		wprintf(L"(IMAGE_FILE_MACHINE_R4000)");
		break;
	case IMAGE_FILE_MACHINE_R10000:
		wprintf(L"(IMAGE_FILE_MACHINE_R10000)");
		break;
	case IMAGE_FILE_MACHINE_WCEMIPSV2:
		wprintf(L"(IMAGE_FILE_MACHINE_WCEMIPSV2)");
		break;
	case IMAGE_FILE_MACHINE_ALPHA:
		wprintf(L"(IMAGE_FILE_MACHINE_ALPHA)");
		break;
	case IMAGE_FILE_MACHINE_SH3:
		wprintf(L"(IMAGE_FILE_MACHINE_SH3)");
		break;
	case IMAGE_FILE_MACHINE_SH3DSP:
		wprintf(L"(IMAGE_FILE_MACHINE_SH3DSP)");
		break;
	case IMAGE_FILE_MACHINE_SH3E:
		wprintf(L"(IMAGE_FILE_MACHINE_SH3E)");
		break;
	case IMAGE_FILE_MACHINE_SH4:
		wprintf(L"(IMAGE_FILE_MACHINE_SH4)");
		break;
	case IMAGE_FILE_MACHINE_SH5:
		wprintf(L"(IMAGE_FILE_MACHINE_SH5)");
		break;
	case IMAGE_FILE_MACHINE_ARM:
		wprintf(L"(IMAGE_FILE_MACHINE_ARM)");
		break;
	case IMAGE_FILE_MACHINE_THUMB:
		wprintf(L"(IMAGE_FILE_MACHINE_THUMB)");
		break;
	case IMAGE_FILE_MACHINE_AM33:
		wprintf(L"(IMAGE_FILE_MACHINE_AM33)");
		break;
	case IMAGE_FILE_MACHINE_POWERPC:
		wprintf(L"(IMAGE_FILE_MACHINE_POWERPC)");
		break;
	case IMAGE_FILE_MACHINE_POWERPCFP:
		wprintf(L"(IMAGE_FILE_MACHINE_POWERPCFP)");
		break;
	case IMAGE_FILE_MACHINE_IA64:
		wprintf(L"(IMAGE_FILE_MACHINE_IA64)");
		break;
	case IMAGE_FILE_MACHINE_MIPS16:
		wprintf(L"(IMAGE_FILE_MACHINE_MIPS16)");
		break;
	case IMAGE_FILE_MACHINE_ALPHA64:
		wprintf(L"(IMAGE_FILE_MACHINE_ALPHA64)");
		break;
	case IMAGE_FILE_MACHINE_MIPSFPU:
		wprintf(L"(IMAGE_FILE_MACHINE_MIPSFPU)");
		break;
	case IMAGE_FILE_MACHINE_MIPSFPU16:
		wprintf(L"(IMAGE_FILE_MACHINE_MIPSFPU16)");
		break;
	case IMAGE_FILE_MACHINE_TRICORE:
		wprintf(L"(IMAGE_FILE_MACHINE_TRICORE)");
		break;
	case IMAGE_FILE_MACHINE_CEF:
		wprintf(L"(IMAGE_FILE_MACHINE_CEF)");
		break;
	case IMAGE_FILE_MACHINE_EBC:
		wprintf(L"(IMAGE_FILE_MACHINE_EBC)");
		break;
	case IMAGE_FILE_MACHINE_AMD64:
		wprintf(L"(IMAGE_FILE_MACHINE_AMD64)");
		break;
	case IMAGE_FILE_MACHINE_M32R:
		wprintf(L"(IMAGE_FILE_MACHINE_M32R)");
		break;
	case IMAGE_FILE_MACHINE_CEE:
		wprintf(L"(IMAGE_FILE_MACHINE_CEE)");
		break;
	default:
		wprintf(L"(Unknown: %d)", machine);
		break;
	}
}

static void s_print_file_characteristics(u2 characteristics)
{
	if(characteristics & IMAGE_FILE_RELOCS_STRIPPED)
		wprintf(L"    (%04Xh) IMAGE_FILE_RELOCS_STRIPPED\n", IMAGE_FILE_RELOCS_STRIPPED);

	if(characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
		wprintf(L"    (%04Xh) IMAGE_FILE_EXECUTABLE_IMAGE\n", IMAGE_FILE_EXECUTABLE_IMAGE);

	if(characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED)
		wprintf(L"    (%04Xh) IMAGE_FILE_LINE_NUMS_STRIPPED\n", IMAGE_FILE_LINE_NUMS_STRIPPED);

	if(characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED)
		wprintf(L"    (%04Xh) IMAGE_FILE_LOCAL_SYMS_STRIPPED\n", IMAGE_FILE_LOCAL_SYMS_STRIPPED);

	if(characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM)
		wprintf(L"    (%04Xh) IMAGE_FILE_AGGRESIVE_WS_TRIM\n", IMAGE_FILE_AGGRESIVE_WS_TRIM);

	if(characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)
		wprintf(L"    (%04Xh) IMAGE_FILE_LARGE_ADDRESS_AWARE\n", IMAGE_FILE_LARGE_ADDRESS_AWARE);

	if(characteristics & IMAGE_FILE_BYTES_REVERSED_LO)
		wprintf(L"    (%04Xh) IMAGE_FILE_BYTES_REVERSED_LO\n", IMAGE_FILE_BYTES_REVERSED_LO);

	if(characteristics & IMAGE_FILE_32BIT_MACHINE)
		wprintf(L"    (%04Xh) IMAGE_FILE_32BIT_MACHINE\n", IMAGE_FILE_32BIT_MACHINE);

	if(characteristics & IMAGE_FILE_DEBUG_STRIPPED)
		wprintf(L"    (%04Xh) IMAGE_FILE_DEBUG_STRIPPED\n", IMAGE_FILE_DEBUG_STRIPPED);

	if(characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)
		wprintf(L"    (%04Xh) IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP\n", IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP);

	if(characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP)
		wprintf(L"    (%04Xh) IMAGE_FILE_NET_RUN_FROM_SWAP\n", IMAGE_FILE_NET_RUN_FROM_SWAP);

	if(characteristics & IMAGE_FILE_SYSTEM)
		wprintf(L"    (%04Xh) IMAGE_FILE_SYSTEM\n", IMAGE_FILE_SYSTEM);

	if(characteristics & IMAGE_FILE_DLL)
		wprintf(L"    (%04Xh) IMAGE_FILE_DLL\n", IMAGE_FILE_DLL);

	if(characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
		wprintf(L"    (%04Xh) IMAGE_FILE_UP_SYSTEM_ONLY\n", IMAGE_FILE_UP_SYSTEM_ONLY);

	if(characteristics & IMAGE_FILE_BYTES_REVERSED_HI)
		wprintf(L"    (%04Xh) IMAGE_FILE_BYTES_REVERSED_HI\n", IMAGE_FILE_BYTES_REVERSED_HI);
}

static void s_print_timestamp(u4 ts)
{
	time_t t = ts;
	char *str = ctime(&t);
	char *p = str;

	while(*p != '\n' && *p != '\0')
		++p;
	*p = '\0';

	printf("(%s)", str);
}

static void s_print_optional_magic(u2 magic)
{
	switch(magic)
	{
	case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
		wprintf(L"(IMAGE_NT_OPTIONAL_HDR32_MAGIC)");
		break;
	case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
		wprintf(L"(IMAGE_NT_OPTIONAL_HDR64_MAGIC)");
		break;
	default:
		wprintf(L"(Unknown: %d)", magic);
		break;
	}
}

static void s_print_optional_subsystem(u2 subsystem)
{
	switch(subsystem)
	{
	case IMAGE_SUBSYSTEM_UNKNOWN:
		wprintf(L"(IMAGE_SUBSYSTEM_UNKNOWN)");
		break;
	case IMAGE_SUBSYSTEM_NATIVE:
		wprintf(L"(IMAGE_SUBSYSTEM_NATIVE)");
		break;
	case IMAGE_SUBSYSTEM_WINDOWS_GUI:
		wprintf(L"(IMAGE_SUBSYSTEM_WINDOWS_GUI)");
		break;
	case IMAGE_SUBSYSTEM_WINDOWS_CUI:
		wprintf(L"(IMAGE_SUBSYSTEM_WINDOWS_CUI)");
		break;
	case IMAGE_SUBSYSTEM_OS2_CUI:
		wprintf(L"(IMAGE_SUBSYSTEM_OS2_CUI)");
		break;
	case IMAGE_SUBSYSTEM_POSIX_CUI:
		wprintf(L"(IMAGE_SUBSYSTEM_POSIX_CUI)");
		break;
	case IMAGE_SUBSYSTEM_NATIVE_WINDOWS:
		wprintf(L"(IMAGE_SUBSYSTEM_NATIVE_WINDOWS)");
		break;
	case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
		wprintf(L"(IMAGE_SUBSYSTEM_WINDOWS_CE_GUI)");
		break;
	case IMAGE_SUBSYSTEM_EFI_APPLICATION:
		wprintf(L"(IMAGE_SUBSYSTEM_EFI_APPLICATION)");
		break;
	case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
		wprintf(L"(IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)");
		break;
	case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
		wprintf(L"(IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)");
		break;
	case IMAGE_SUBSYSTEM_EFI_ROM:
		wprintf(L"(IMAGE_SUBSYSTEM_EFI_ROM)");
		break;
	case IMAGE_SUBSYSTEM_XBOX:
		wprintf(L"(IMAGE_SUBSYSTEM_XBOX)");
		break;
	case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:
		wprintf(L"(IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)");
		break;
	default:
		wprintf(L"(Unknown: %d)", subsystem);
		break;
	}
}

static void s_print_dll_characteristics(u2 characteristics)
{
	if(characteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE\n", IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE);

	if(characteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY\n", IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY);

	if(characteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_NX_COMPAT\n", IMAGE_DLLCHARACTERISTICS_NX_COMPAT);

	if(characteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_NO_ISOLATION\n", IMAGE_DLLCHARACTERISTICS_NO_ISOLATION);

	if(characteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_NO_SEH\n", IMAGE_DLLCHARACTERISTICS_NO_SEH);

	if(characteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_NO_BIND\n", IMAGE_DLLCHARACTERISTICS_NO_BIND);

	if(characteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_WDM_DRIVER\n", IMAGE_DLLCHARACTERISTICS_WDM_DRIVER);

	if(characteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)
		wprintf(L"    (%04Xh) IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE\n", IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE);
}

static void s_print_data_directoies(pe_file *p_pe)
{
	byte *pb = p_pe->p_base;
	image_data_directory *ph = IS_64BIT_PE(p_pe)
		? p_pe->p_headers64->OptionalHeader.DataDirectory
		: p_pe->p_headers32->OptionalHeader.DataDirectory;
	wchar_t val_buf[DATA_DIRECTORY_STR_LEN];
	int i;

	for(i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; ++i, ++ph)
	{
		wmemchr(val_buf, L'\0', DATA_DIRECTORY_STR_LEN);
		format_data_dir(p_pe, ph, val_buf, DATA_DIRECTORY_STR_LEN - 1);
		wprintf(L"%08Xh ", PTR_D(pb, ph));
		wprintf(L"%01Xh ", sizeof(*ph));
		wprintf(L"DataDirectory[%2d] %14s ", i, s_dd_names[i]);
		wprintf(val_buf);
		wprintf(L"\n");
	}
}

static void s_print_optional_header32(pe_file *p_pe)
{
	byte *pb = p_pe->p_base;
	image_optional_header32 *ph = &p_pe->p_headers32->OptionalHeader;

	wprintf(L"IMAGE_OPTIONAL_HEADER32:\n");

	// Standard fields.

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Magic));
	wprintf(L"%01Xh ", sizeof(ph->Magic));
	wprintf(L"%27s ", L"Magic");
	wprintf(L"%04Xh     ", ph->Magic);
	s_print_optional_magic(ph->Magic);
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorLinkerVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorLinkerVersion));
	wprintf(L"%27s ", L"MajorLinkerVersion");
	wprintf(L"%02Xh       (%d)\n", ph->MajorLinkerVersion, ph->MajorLinkerVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorLinkerVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorLinkerVersion));
	wprintf(L"%27s ", L"MinorLinkerVersion");
	wprintf(L"%02Xh       (%d)\n", ph->MinorLinkerVersion, ph->MinorLinkerVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfCode));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfCode));
	wprintf(L"%27s ", L"SizeOfCode");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfCode, ph->SizeOfCode);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfInitializedData));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfInitializedData));
	wprintf(L"%27s ", L"SizeOfInitializedData");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfInitializedData, ph->SizeOfInitializedData);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfUninitializedData));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfUninitializedData));
	wprintf(L"%27s ", L"SizeOfUninitializedData");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfUninitializedData, ph->SizeOfUninitializedData);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->AddressOfEntryPoint));
	wprintf(L"%01Xh ", sizeof(ph->AddressOfEntryPoint));
	wprintf(L"%27s ", L"AddressOfEntryPoint");
	wprintf(L"%08Xh\n", ph->AddressOfEntryPoint);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->BaseOfCode));
	wprintf(L"%01Xh ", sizeof(ph->BaseOfCode));
	wprintf(L"%27s ", L"BaseOfCode");
	wprintf(L"%08Xh\n", ph->BaseOfCode);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->BaseOfData));
	wprintf(L"%01Xh ", sizeof(ph->BaseOfData));
	wprintf(L"%27s ", L"BaseOfData");
	wprintf(L"%08Xh\n", ph->BaseOfData);

	// Standard fields.

	wprintf(L"%08Xh ", PTR_D(pb, &ph->ImageBase));
	wprintf(L"%01Xh ", sizeof(ph->ImageBase));
	wprintf(L"%27s ", L"ImageBase");
	wprintf(L"%08Xh\n", ph->ImageBase);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SectionAlignment));
	wprintf(L"%01Xh ", sizeof(ph->SectionAlignment));
	wprintf(L"%27s ", L"SectionAlignment");
	wprintf(L"%08Xh\n", ph->SectionAlignment);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->FileAlignment));
	wprintf(L"%01Xh ", sizeof(ph->FileAlignment));
	wprintf(L"%27s ", L"FileAlignment");
	wprintf(L"%08Xh\n", ph->FileAlignment);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorOperatingSystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorOperatingSystemVersion));
	wprintf(L"%27s ", L"MajorOperatingSystemVersion");
	wprintf(L"%04Xh     (%d)\n", ph->MajorOperatingSystemVersion, ph->MajorOperatingSystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorOperatingSystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorOperatingSystemVersion));
	wprintf(L"%27s ", L"MinorOperatingSystemVersion");
	wprintf(L"%04Xh     (%d)\n", ph->MinorOperatingSystemVersion, ph->MinorOperatingSystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorImageVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorImageVersion));
	wprintf(L"%27s ", L"MajorImageVersion");
	wprintf(L"%04Xh     (%d)\n", ph->MajorImageVersion, ph->MajorImageVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorImageVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorImageVersion));
	wprintf(L"%27s ", L"MinorImageVersion");
	wprintf(L"%04Xh     (%d)\n", ph->MinorImageVersion, ph->MinorImageVersion);
	

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorSubsystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorSubsystemVersion));
	wprintf(L"%27s ", L"MajorSubsystemVersion");
	wprintf(L"%04Xh     (%d)\n", ph->MajorSubsystemVersion, ph->MajorSubsystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorSubsystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorSubsystemVersion));
	wprintf(L"%27s ", L"MinorSubsystemVersion");
	wprintf(L"%04Xh     (%d)\n", ph->MinorSubsystemVersion, ph->MinorSubsystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Win32VersionValue));
	wprintf(L"%01Xh ", sizeof(ph->Win32VersionValue));
	wprintf(L"%27s ", L"Win32VersionValue");
	wprintf(L"%08Xh\n", ph->Win32VersionValue);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfImage));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfImage));
	wprintf(L"%27s ", L"SizeOfImage");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfImage, ph->SizeOfImage);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfHeaders));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfHeaders));
	wprintf(L"%27s ", L"SizeOfHeaders");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfHeaders, ph->SizeOfHeaders);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->CheckSum));
	wprintf(L"%01Xh ", sizeof(ph->CheckSum));
	wprintf(L"%27s ", L"CheckSum");
	wprintf(L"%08Xh\n", ph->CheckSum);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Subsystem));
	wprintf(L"%01Xh ", sizeof(ph->Subsystem));
	wprintf(L"%27s ", L"Subsystem");
	wprintf(L"%04Xh     ", ph->Subsystem);
	s_print_optional_subsystem(ph->Subsystem);
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->DllCharacteristics));
	wprintf(L"%01Xh ", sizeof(ph->DllCharacteristics));
	wprintf(L"%27s ", L"DllCharacteristics");
	wprintf(L"%04Xh\n", ph->DllCharacteristics);
	s_print_dll_characteristics(ph->DllCharacteristics);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfStackReserve));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfStackReserve));
	wprintf(L"%27s ", L"SizeOfStackReserve");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfStackReserve, ph->SizeOfStackReserve);
	

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfStackCommit));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfStackCommit));
	wprintf(L"%27s ", L"SizeOfStackCommit");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfStackCommit, ph->SizeOfStackCommit);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfHeapReserve));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfHeapReserve));
	wprintf(L"%27s ", L"SizeOfHeapReserve");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfHeapReserve, ph->SizeOfHeapReserve);
	

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfHeapCommit));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfHeapCommit));
	wprintf(L"%27s ", L"SizeOfHeapCommit");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfHeapCommit, ph->SizeOfHeapCommit);
	

	wprintf(L"%08Xh ", PTR_D(pb, &ph->LoaderFlags));
	wprintf(L"%01Xh ", sizeof(ph->LoaderFlags));
	wprintf(L"%27s ", L"LoaderFlags");
	wprintf(L"%08Xh\n", ph->LoaderFlags);
	

	wprintf(L"%08Xh ", PTR_D(pb, &ph->NumberOfRvaAndSizes));
	wprintf(L"%01Xh ", sizeof(ph->NumberOfRvaAndSizes));
	wprintf(L"%27s ", L"NumberOfRvaAndSizes");
	wprintf(L"%08Xh (%d)\n", ph->NumberOfRvaAndSizes, ph->NumberOfRvaAndSizes);

	wprintf(L"\n");

	s_print_data_directoies(p_pe);
}

static void s_print_optional_header64(pe_file *p_pe)
{
	byte *pb = p_pe->p_base;
	image_optional_header64 *ph = &p_pe->p_headers64->OptionalHeader;

	wprintf(L"IMAGE_OPTIONAL_HEADER64:\n");

	// Standard fields.

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Magic));
	wprintf(L"%01Xh ", sizeof(ph->Magic));
	wprintf(L"%27s ", L"Magic");
	wprintf(L"%04Xh             ", ph->Magic);
	s_print_optional_magic(ph->Magic);
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorLinkerVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorLinkerVersion));
	wprintf(L"%27s ", L"MajorLinkerVersion");
	wprintf(L"%02Xh               (%d)\n", ph->MajorLinkerVersion, ph->MajorLinkerVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorLinkerVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorLinkerVersion));
	wprintf(L"%27s ", L"MinorLinkerVersion");
	wprintf(L"%02Xh               (%d)\n", ph->MinorLinkerVersion, ph->MinorLinkerVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfCode));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfCode));
	wprintf(L"%27s ", L"SizeOfCode");
	wprintf(L"%08Xh         (%d)\n", ph->SizeOfCode, ph->SizeOfCode);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfInitializedData));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfInitializedData));
	wprintf(L"%27s ", L"SizeOfInitializedData");
	wprintf(L"%08Xh         (%d)\n", ph->SizeOfInitializedData, ph->SizeOfInitializedData);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfUninitializedData));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfUninitializedData));
	wprintf(L"%27s ", L"SizeOfUninitializedData");
	wprintf(L"%08Xh         (%d)\n", ph->SizeOfUninitializedData, ph->SizeOfUninitializedData);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->AddressOfEntryPoint));
	wprintf(L"%01Xh ", sizeof(ph->AddressOfEntryPoint));
	wprintf(L"%27s ", L"AddressOfEntryPoint");
	wprintf(L"%08Xh\n", ph->AddressOfEntryPoint);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->BaseOfCode));
	wprintf(L"%01Xh ", sizeof(ph->BaseOfCode));
	wprintf(L"%27s ", L"BaseOfCode");
	wprintf(L"%08Xh\n", ph->BaseOfCode);

	// Standard fields.

	wprintf(L"%08Xh ", PTR_D(pb, &ph->ImageBase));
	wprintf(L"%01Xh ", sizeof(ph->ImageBase));
	wprintf(L"%27s ", L"ImageBase");
	wprintf(L"%016Xh\n", ph->ImageBase);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SectionAlignment));
	wprintf(L"%01Xh ", sizeof(ph->SectionAlignment));
	wprintf(L"%27s ", L"SectionAlignment");
	wprintf(L"%08Xh\n", ph->SectionAlignment);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->FileAlignment));
	wprintf(L"%01Xh ", sizeof(ph->FileAlignment));
	wprintf(L"%27s ", L"FileAlignment");
	wprintf(L"%08Xh\n", ph->FileAlignment);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorOperatingSystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorOperatingSystemVersion));
	wprintf(L"%27s ", L"MajorOperatingSystemVersion");
	wprintf(L"%04Xh             (%d)\n", ph->MajorOperatingSystemVersion, ph->MajorOperatingSystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorOperatingSystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorOperatingSystemVersion));
	wprintf(L"%27s ", L"MinorOperatingSystemVersion");
	wprintf(L"%04Xh             (%d)\n", ph->MinorOperatingSystemVersion, ph->MinorOperatingSystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorImageVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorImageVersion));
	wprintf(L"%27s ", L"MajorImageVersion");
	wprintf(L"%04Xh             (%d)\n", ph->MajorImageVersion, ph->MajorImageVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorImageVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorImageVersion));
	wprintf(L"%27s ", L"MinorImageVersion");
	wprintf(L"%04Xh             (%d)\n", ph->MinorImageVersion, ph->MinorImageVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MajorSubsystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MajorSubsystemVersion));
	wprintf(L"%27s ", L"MajorSubsystemVersion");
	wprintf(L"%04Xh             (%d)\n", ph->MajorSubsystemVersion, ph->MajorSubsystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->MinorSubsystemVersion));
	wprintf(L"%01Xh ", sizeof(ph->MinorSubsystemVersion));
	wprintf(L"%27s ", L"MinorSubsystemVersion");
	wprintf(L"%04Xh             (%d)\n", ph->MinorSubsystemVersion, ph->MinorSubsystemVersion);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Win32VersionValue));
	wprintf(L"%01Xh ", sizeof(ph->Win32VersionValue));
	wprintf(L"%27s ", L"Win32VersionValue");
	wprintf(L"%08Xh\n", ph->Win32VersionValue);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfImage));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfImage));
	wprintf(L"%27s ", L"SizeOfImage");
	wprintf(L"%08Xh         (%d)\n", ph->SizeOfImage, ph->SizeOfImage);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfHeaders));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfHeaders));
	wprintf(L"%27s ", L"SizeOfHeaders");
	wprintf(L"%08Xh         (%d)\n", ph->SizeOfHeaders, ph->SizeOfHeaders);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->CheckSum));
	wprintf(L"%01Xh ", sizeof(ph->CheckSum));
	wprintf(L"%27s ", L"CheckSum");
	wprintf(L"%08Xh\n", ph->CheckSum);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Subsystem));
	wprintf(L"%01Xh ", sizeof(ph->Subsystem));
	wprintf(L"%27s ", L"Subsystem");
	wprintf(L"%04Xh             ", ph->Subsystem);
	s_print_optional_subsystem(ph->Subsystem);
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->DllCharacteristics));
	wprintf(L"%01Xh ", sizeof(ph->DllCharacteristics));
	wprintf(L"%27s ", L"DllCharacteristics");
	wprintf(L"%04Xh\n", ph->DllCharacteristics);
	s_print_dll_characteristics(ph->DllCharacteristics);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfStackReserve));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfStackReserve));
	wprintf(L"%27s ", L"SizeOfStackReserve");
	wprintf(L"%016Xh (%d)\n", ph->SizeOfStackReserve, ph->SizeOfStackReserve);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfStackCommit));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfStackCommit));
	wprintf(L"%27s ", L"SizeOfStackCommit");
	wprintf(L"%016Xh (%d)\n", ph->SizeOfStackCommit, ph->SizeOfStackCommit);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfHeapReserve));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfHeapReserve));
	wprintf(L"%27s ", L"SizeOfHeapReserve");
	wprintf(L"%016Xh (%d)\n", ph->SizeOfHeapReserve, ph->SizeOfHeapReserve);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfHeapCommit));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfHeapCommit));
	wprintf(L"%27s ", L"SizeOfHeapCommit");
	wprintf(L"%016Xh (%d)\n", ph->SizeOfHeapCommit, ph->SizeOfHeapCommit);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->LoaderFlags));
	wprintf(L"%01Xh ", sizeof(ph->LoaderFlags));
	wprintf(L"%27s ", L"LoaderFlags");
	wprintf(L"%08Xh\n", ph->LoaderFlags);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->NumberOfRvaAndSizes));
	wprintf(L"%01Xh ", sizeof(ph->NumberOfRvaAndSizes));
	wprintf(L"%27s ", L"NumberOfRvaAndSizes");
	wprintf(L"%08Xh         (%d)\n", ph->NumberOfRvaAndSizes, ph->NumberOfRvaAndSizes);

	wprintf(L"\n");

	s_print_data_directoies(p_pe);
}

static void s_print_section_characteristics(u4 characteristics)
{
	if(characteristics & IMAGE_SCN_TYPE_NO_PAD)
		wprintf(L"    (%08Xh) IMAGE_SCN_TYPE_NO_PAD\n", IMAGE_SCN_TYPE_NO_PAD);

	if(characteristics & IMAGE_SCN_CNT_CODE)
		wprintf(L"    (%08Xh) IMAGE_SCN_CNT_CODE\n", IMAGE_SCN_CNT_CODE);

	if(characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
		wprintf(L"    (%08Xh) IMAGE_SCN_CNT_INITIALIZED_DATA\n", IMAGE_SCN_CNT_INITIALIZED_DATA);

	if(characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
		wprintf(L"    (%08Xh) IMAGE_SCN_CNT_UNINITIALIZED_DATA\n", IMAGE_SCN_CNT_UNINITIALIZED_DATA);

	if(characteristics & IMAGE_SCN_LNK_OTHER)
		wprintf(L"    (%08Xh) IMAGE_SCN_LNK_OTHER\n", IMAGE_SCN_LNK_OTHER);

	if(characteristics & IMAGE_SCN_LNK_INFO)
		wprintf(L"    (%08Xh) IMAGE_SCN_LNK_INFO\n", IMAGE_SCN_LNK_INFO);

	if(characteristics & IMAGE_SCN_LNK_REMOVE)
		wprintf(L"    (%08Xh) IMAGE_SCN_LNK_REMOVE\n", IMAGE_SCN_LNK_REMOVE);

	if(characteristics & IMAGE_SCN_LNK_COMDAT)
		wprintf(L"    (%08Xh) IMAGE_SCN_LNK_COMDAT\n", IMAGE_SCN_LNK_COMDAT);

	if(characteristics & IMAGE_SCN_NO_DEFER_SPEC_EXC)
		wprintf(L"    (%08Xh) IMAGE_SCN_NO_DEFER_SPEC_EXC\n", IMAGE_SCN_NO_DEFER_SPEC_EXC);

	if(characteristics & IMAGE_SCN_GPREL)
		wprintf(L"    (%08Xh) IMAGE_SCN_GPREL\n", IMAGE_SCN_GPREL);

	if(characteristics & IMAGE_SCN_MEM_FARDATA)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_FARDATA\n", IMAGE_SCN_MEM_FARDATA);

	if(characteristics & IMAGE_SCN_MEM_PURGEABLE)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_PURGEABLE\n", IMAGE_SCN_MEM_PURGEABLE);

	if(characteristics & IMAGE_SCN_MEM_16BIT)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_16BIT\n", IMAGE_SCN_MEM_16BIT);

	if(characteristics & IMAGE_SCN_MEM_LOCKED)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_LOCKED\n", IMAGE_SCN_MEM_LOCKED);

	if(characteristics & IMAGE_SCN_MEM_PRELOAD)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_PRELOAD\n", IMAGE_SCN_MEM_PRELOAD);

	switch(characteristics & IMAGE_SCN_ALIGN_MASK)
	{
	case IMAGE_SCN_ALIGN_1BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_1BYTES\n", IMAGE_SCN_ALIGN_1BYTES);
		break;

	case IMAGE_SCN_ALIGN_2BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_2BYTES\n", IMAGE_SCN_ALIGN_2BYTES);
		break;

	case IMAGE_SCN_ALIGN_4BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_4BYTES\n", IMAGE_SCN_ALIGN_4BYTES);
		break;

	case IMAGE_SCN_ALIGN_8BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_8BYTES\n", IMAGE_SCN_ALIGN_8BYTES);
		break;

	case IMAGE_SCN_ALIGN_16BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_16BYTES\n", IMAGE_SCN_ALIGN_16BYTES);
		break;

	case IMAGE_SCN_ALIGN_32BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_32BYTES\n", IMAGE_SCN_ALIGN_32BYTES);
		break;

	case IMAGE_SCN_ALIGN_64BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_64BYTES\n", IMAGE_SCN_ALIGN_64BYTES);
		break;

	case IMAGE_SCN_ALIGN_128BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_128BYTES\n", IMAGE_SCN_ALIGN_128BYTES);
		break;

	case IMAGE_SCN_ALIGN_256BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_256BYTES\n", IMAGE_SCN_ALIGN_256BYTES);
		break;

	case IMAGE_SCN_ALIGN_512BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_512BYTES\n", IMAGE_SCN_ALIGN_512BYTES);
		break;

	case IMAGE_SCN_ALIGN_1024BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_1024BYTES\n", IMAGE_SCN_ALIGN_1024BYTES);
		break;

	case IMAGE_SCN_ALIGN_2048BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_2048BYTES\n", IMAGE_SCN_ALIGN_2048BYTES);
		break;

	case IMAGE_SCN_ALIGN_4096BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_4096BYTES\n", IMAGE_SCN_ALIGN_4096BYTES);
		break;

	case IMAGE_SCN_ALIGN_8192BYTES:
		wprintf(L"    (%08Xh) IMAGE_SCN_ALIGN_8192BYTES\n", IMAGE_SCN_ALIGN_8192BYTES);
		break;
	}

	if(characteristics & IMAGE_SCN_LNK_NRELOC_OVFL)
		wprintf(L"    (%08Xh) IMAGE_SCN_LNK_NRELOC_OVFL\n", IMAGE_SCN_LNK_NRELOC_OVFL);

	if(characteristics & IMAGE_SCN_MEM_DISCARDABLE)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_DISCARDABLE\n", IMAGE_SCN_MEM_DISCARDABLE);

	if(characteristics & IMAGE_SCN_MEM_NOT_CACHED)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_NOT_CACHED\n", IMAGE_SCN_MEM_NOT_CACHED);

	if(characteristics & IMAGE_SCN_MEM_NOT_PAGED)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_NOT_PAGED\n", IMAGE_SCN_MEM_NOT_PAGED);

	if(characteristics & IMAGE_SCN_MEM_SHARED)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_SHARED\n", IMAGE_SCN_MEM_SHARED);

	if(characteristics & IMAGE_SCN_MEM_EXECUTE)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_EXECUTE\n", IMAGE_SCN_MEM_EXECUTE);

	if(characteristics & IMAGE_SCN_MEM_READ)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_READ\n", IMAGE_SCN_MEM_READ);

	if(characteristics & IMAGE_SCN_MEM_WRITE)
		wprintf(L"    (%08Xh) IMAGE_SCN_MEM_WRITE\n", IMAGE_SCN_MEM_WRITE);
}

static void s_print_section_header(pe_file *p_pe, int n)
{
	byte *pb = p_pe->p_base;
	image_section_header *ph = IS_64BIT_PE(p_pe)
		? &p_pe->p_headers64->SectionHeaders[n]
		: &p_pe->p_headers32->SectionHeaders[n];

	wprintf(L"IMAGE_SECTION_HEADER[%d]:\n", n);

	if(n < 0 || n >= p_pe->p_headers32->FileHeader.NumberOfSections)
	{
		wprintf(L"Index out of range (0-%d).\n",
			p_pe->p_headers32->FileHeader.NumberOfSections);
		return;
	}

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Name));
	wprintf(L"%01Xh ", sizeof(ph->Name));
	wprintf(L"%20s ", L"Name");
	{
		int i;

		for(i = 0; i < IMAGE_SIZEOF_SHORT_NAME; ++i)
			wprintf(L"%02X ", ph->Name[i]);

		for(i = 0; i < IMAGE_SIZEOF_SHORT_NAME && ph->Name[i] != 0; ++i)
			wprintf(L"%c", ph->Name[i]);

		wprintf(L"\n");
	}

	wprintf(L"%08Xh ", PTR_D(pb, &ph->VirtualSize));
	wprintf(L"%01Xh ", sizeof(ph->VirtualSize));
	wprintf(L"%20s ", L"VirtualSize");
	wprintf(L"%08Xh (%d)\n", ph->VirtualSize, ph->VirtualSize);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->VirtualAddress));
	wprintf(L"%01Xh ", sizeof(ph->VirtualAddress));
	wprintf(L"%20s ", L"VirtualAddress");
	wprintf(L"%08Xh\n", ph->VirtualAddress);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfRawData));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfRawData));
	wprintf(L"%20s ", L"SizeOfRawData");
	wprintf(L"%08Xh (%d)\n", ph->SizeOfRawData, ph->SizeOfRawData);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->PointerToRawData));
	wprintf(L"%01Xh ", sizeof(ph->PointerToRawData));
	wprintf(L"%20s ", L"PointerToRawData");
	wprintf(L"%08Xh\n", ph->PointerToRawData);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->PointerToRelocations));
	wprintf(L"%01Xh ", sizeof(ph->PointerToRelocations));
	wprintf(L"%20s ", L"PointerToRelocations");
	wprintf(L"%08Xh\n", ph->PointerToRelocations);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->PointerToLinenumbers));
	wprintf(L"%01Xh ", sizeof(ph->PointerToLinenumbers));
	wprintf(L"%20s ", L"PointerToLinenumbers");
	wprintf(L"%08Xh\n", ph->PointerToLinenumbers);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->NumberOfRelocations));
	wprintf(L"%01Xh ", sizeof(ph->NumberOfRelocations));
	wprintf(L"%20s ", L"NumberOfRelocations");
	wprintf(L"%04Xh     (%d)\n", ph->NumberOfRelocations, ph->NumberOfRelocations);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->NumberOfLinenumbers));
	wprintf(L"%01Xh ", sizeof(ph->NumberOfLinenumbers));
	wprintf(L"%20s ", L"NumberOfLinenumbers");
	wprintf(L"%04Xh     (%d)\n", ph->NumberOfLinenumbers, ph->NumberOfLinenumbers);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Characteristics));
	wprintf(L"%01Xh ", sizeof(ph->Characteristics));
	wprintf(L"%20s ", L"Characteristics");
	wprintf(L"%08Xh\n", ph->Characteristics);
	s_print_section_characteristics(ph->Characteristics);
}

/****************************************************************************\
 * Public Functions
\****************************************************************************/

void print_dos_header(pe_file *p_pe)
{
	byte *pb = p_pe->p_base;
	image_dos_header *ph = p_pe->p_dos_header;

	if(!check_file_opened() || !check_pe_headers(p_pe))
		return;

	wprintf(L"IMAGE_DOS_HEADER:\n");
	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_magic));
	wprintf(L"%2Xh ", sizeof(ph->e_magic));
	wprintf(L"%10s ", L"e_magic");
	wprintf(L"%04Xh\n", ph->e_magic);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_cblp));
	wprintf(L"%2Xh ", sizeof(ph->e_cblp));
	wprintf(L"%10s ", L"e_cblp");
	wprintf(L"%04Xh\n", ph->e_cblp);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_cp));
	wprintf(L"%2Xh ", sizeof(ph->e_cp));
	wprintf(L"%10s ", L"e_cp");
	wprintf(L"%04Xh\n", ph->e_cp);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_crlc));
	wprintf(L"%2Xh ", sizeof(ph->e_crlc));
	wprintf(L"%10s ", L"e_crlc");
	wprintf(L"%04Xh\n", ph->e_crlc);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_cparhdr));
	wprintf(L"%2Xh ", sizeof(ph->e_cparhdr));
	wprintf(L"%10s ", L"e_cparhdr");
	wprintf(L"%04Xh\n", ph->e_cparhdr);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_minalloc));
	wprintf(L"%2Xh ", sizeof(ph->e_minalloc));
	wprintf(L"%10s ", L"e_minalloc");
	wprintf(L"%04Xh\n", ph->e_minalloc);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_maxalloc));
	wprintf(L"%2Xh ", sizeof(ph->e_maxalloc));
	wprintf(L"%10s ", L"e_maxalloc");
	wprintf(L"%04Xh\n", ph->e_maxalloc);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_ss));
	wprintf(L"%2Xh ", sizeof(ph->e_ss));
	wprintf(L"%10s ", L"e_ss");
	wprintf(L"%04Xh\n", ph->e_ss);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_sp));
	wprintf(L"%2Xh ", sizeof(ph->e_sp));
	wprintf(L"%10s ", L"e_sp");
	wprintf(L"%04Xh\n", ph->e_sp);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_csum));
	wprintf(L"%2Xh ", sizeof(ph->e_csum));
	wprintf(L"%10s ", L"e_csum");
	wprintf(L"%04Xh\n", ph->e_csum);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_ip));
	wprintf(L"%2Xh ", sizeof(ph->e_ip));
	wprintf(L"%10s ", L"e_ip");
	wprintf(L"%04Xh\n", ph->e_ip);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_cs));
	wprintf(L"%2Xh ", sizeof(ph->e_cs));
	wprintf(L"%10s ", L"e_cs");
	wprintf(L"%04Xh\n", ph->e_cs);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_lfarlc));
	wprintf(L"%2Xh ", sizeof(ph->e_lfarlc));
	wprintf(L"%10s ", L"e_lfarlc");
	wprintf(L"%04Xh\n", ph->e_lfarlc);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_ovno));
	wprintf(L"%2Xh ", sizeof(ph->e_ovno));
	wprintf(L"%10s ", L"e_ovno");
	wprintf(L"%04Xh\n", ph->e_ovno);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_res));
	wprintf(L"%2Xh ", sizeof(ph->e_res));
	wprintf(L"%10s ", L"e_res");
	{
		size_t i;
		for(i = 0; i < sizeof(ph->e_res) / sizeof(ph->e_res[0]); ++i)
			wprintf(L"%04X ", ph->e_res[i]);
	}
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_oemid));
	wprintf(L"%2Xh ", sizeof(ph->e_oemid));
	wprintf(L"%10s ", L"e_oemid");
	wprintf(L"%04Xh\n", ph->e_oemid);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_oeminfo));
	wprintf(L"%2Xh ", sizeof(ph->e_oeminfo));
	wprintf(L"%10s ", L"e_oeminfo");
	wprintf(L"%04Xh\n", ph->e_oeminfo);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_res2));
	wprintf(L"%2Xh ", sizeof(ph->e_res2));
	wprintf(L"%10s ", L"e_res2");
	{
		size_t i;
		for(i = 0; i < sizeof(ph->e_res2) / sizeof(ph->e_res2[0]); ++i)
			wprintf(L"%04X ", ph->e_res2[i]);
	}
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->e_lfanew));
	wprintf(L"%2Xh ", sizeof(ph->e_lfanew));
	wprintf(L"%10s ", L"e_lfanew");
	wprintf(L"%08Xh\n", ph->e_lfanew);
}

void print_pe_sig(pe_file *p_pe)
{
	byte *pb = p_pe->p_base;
	image_all_headers32 *ph = p_pe->p_headers32;

	if(!check_file_opened() || !check_pe_headers(p_pe))
		return;

	wprintf(L"PE Signature:\n");
	wprintf(L"%08Xh ", PTR_D(pb, &ph->Signature));
	wprintf(L"%01Xh ", sizeof(ph->Signature));
	wprintf(L"%9s ", L"Signature");
	wprintf(L"%08Xh\n", ph->Signature);
}

void print_file_header(pe_file *p_pe)
{
	byte *pb = p_pe->p_base;
	image_file_header *ph = &p_pe->p_headers32->FileHeader;

	if(!check_file_opened() || !check_pe_headers(p_pe))
		return;

	wprintf(L"IMAGE_FILE_HEADER:\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Machine));
	wprintf(L"%01Xh ", sizeof(ph->Machine));
	wprintf(L"%20s ", L"Machine");
	wprintf(L"%04Xh     ", ph->Machine);
	s_print_file_machine(ph->Machine);
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->NumberOfSections));
	wprintf(L"%01Xh ", sizeof(ph->NumberOfSections));
	wprintf(L"%20s ", L"NumberOfSections");
	wprintf(L"%04Xh     (%d)\n", ph->NumberOfSections, ph->NumberOfSections);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->TimeDateStamp));
	wprintf(L"%01Xh ", sizeof(ph->TimeDateStamp));
	wprintf(L"%20s ", L"TimeDateStamp");
	wprintf(L"%08Xh ", ph->TimeDateStamp);
	s_print_timestamp(ph->TimeDateStamp);
	wprintf(L"\n");

	wprintf(L"%08Xh ", PTR_D(pb, &ph->PointerToSymbolTable));
	wprintf(L"%01Xh ", sizeof(ph->PointerToSymbolTable));
	wprintf(L"%20s ", L"PointerToSymbolTable");
	wprintf(L"%08Xh\n", ph->PointerToSymbolTable);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->NumberOfSymbols));
	wprintf(L"%01Xh ", sizeof(ph->NumberOfSymbols));
	wprintf(L"%20s ", L"NumberOfSymbols");
	wprintf(L"%08Xh (%d)\n", ph->NumberOfSymbols, ph->NumberOfSymbols);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->SizeOfOptionalHeader));
	wprintf(L"%01Xh ", sizeof(ph->SizeOfOptionalHeader));
	wprintf(L"%20s ", L"SizeOfOptionalHeader");
	wprintf(L"%04Xh     (%d)\n", ph->SizeOfOptionalHeader, ph->SizeOfOptionalHeader);

	wprintf(L"%08Xh ", PTR_D(pb, &ph->Characteristics));
	wprintf(L"%01Xh ", sizeof(ph->Characteristics));
	wprintf(L"%20s ", L"Characteristics");
	wprintf(L"%04Xh\n", ph->Characteristics);
	s_print_file_characteristics(ph->Characteristics);
}

void print_optional_header(pe_file *p_pe)
{
	if(!check_file_opened() || !check_pe_headers(p_pe))
		return;

	if(IS_64BIT_PE(p_pe))
		s_print_optional_header64(p_pe);
	else
		s_print_optional_header32(p_pe);
}

void print_section_headers(pe_file *p_pe)
{
	int i;

	if(!check_file_opened() || !check_pe_headers(p_pe))
		return;

	if(p_pe->p_headers64->FileHeader.NumberOfSections > 0)
		s_print_section_header(p_pe, 0);

	for(i = 1; i < p_pe->p_headers64->FileHeader.NumberOfSections; ++i)
	{
		wprintf(L"\n");
		s_print_section_header(p_pe, i);
	}
}

void print_nt_headers(pe_file *p_pe)
{
	if(!check_file_opened() || !check_pe_headers(p_pe))
		return;

	print_pe_sig(p_pe);
	wprintf(L"\n");
	print_file_header(p_pe);
	wprintf(L"\n");
	print_optional_header(p_pe);
	wprintf(L"\n");
	print_section_headers(p_pe);
}
